/**
 * @file utils.cpp
 * @brief 工具函数实现
 * @details 实现了文件操作、字符串处理、时间戳转换、网络请求等通用功能
 */

#include "utils.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstring>
#include <gtk/gtk.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "lyric_log.h"

/**
 * @brief 交换两个double类型的变量值
 * @param xp 第一个double变量的指针
 * @param yp 第二个double变量的指针
 */
void swap(double *xp, double *yp)
{
    double temp = *xp;
    *xp = *yp;
    *yp = temp;
}

/**
 * @brief 交换两个gchar*类型的变量值
 * @param xp 第一个gchar*变量的指针
 * @param yp 第二个gchar*变量的指针
 */
void swaptext(gchar** xp, gchar** yp)
{
    gchar* temp = *xp;
    *xp = *yp;
    *yp = temp;
}

/**
 * @brief 分割字符串
 * @param s 要分割的字符串
 * @param delimiter 分隔符
 * @param count 返回分割后的字符串数量
 * @return 分割后的字符串数组（需要调用者释放内存）
 */
gchar** split(const gchar* s, const gchar* delimiter, gint* count) {
    if (!s || !delimiter || !count) {
        *count = 0;
        return NULL;
    }
    
    // 使用 GLib 的字符串分割函数
    return g_strsplit(s, delimiter, -1);
}


/**
 * @brief 转换字符串编码为UTF-8（用于从deadbeef API获取的元数据字符串）
 * @param str 输入字符串
 * @return 转换后的UTF-8字符串（需要调用者释放内存），如果输入为NULL则返回NULL
 */
gchar* convert_to_utf8(const gchar* str)
{
    if (!str) {
        return NULL;
    }
    
    // 如果已经是有效的UTF-8，直接返回副本
    if (g_utf8_validate(str, -1, NULL)) {
        return g_strdup(str);
    }
    
    // 尝试各种编码转换
    gchar* result = NULL;
    gsize bytes_read = 0;
    gsize bytes_written = 0;
    GError* error = NULL;
    
#ifdef _WIN32
    // Windows下优先尝试本地编码（通常是GBK或CP936）
    result = g_locale_to_utf8(str, -1, &bytes_read, &bytes_written, &error);
    if (result && !error) {
        return result;
    }
    if (error) {
        g_error_free(error);
        error = NULL;
    }
    g_free(result);
    result = NULL;
    
    // 如果失败，尝试GBK编码
    result = g_convert(str, -1, "UTF-8", "GBK", &bytes_read, &bytes_written, &error);
    if (result && !error) {
        return result;
    }
    if (error) {
        g_error_free(error);
        error = NULL;
    }
    g_free(result);
    result = NULL;
    
    // 最后尝试CP936
    result = g_convert(str, -1, "UTF-8", "CP936", &bytes_read, &bytes_written, &error);
    if (result && !error) {
        return result;
    }
    if (error) {
        g_error_free(error);
        error = NULL;
    }
#else
    // Linux下尝试常见的编码转换
    // 首先尝试GBK（中文Windows常见编码）
    result = g_convert(str, -1, "UTF-8", "GBK", &bytes_read, &bytes_written, &error);
    if (result && !error) {
        return result;
    }
    if (error) {
        g_error_free(error);
        error = NULL;
    }
    g_free(result);
    result = NULL;
    
    // 尝试GB18030（中文Linux常见编码）
    result = g_convert(str, -1, "UTF-8", "GB18030", &bytes_read, &bytes_written, &error);
    if (result && !error) {
        return result;
    }
    if (error) {
        g_error_free(error);
        error = NULL;
    }
    g_free(result);
    result = NULL;
    
    // 尝试ISO-8859-1（Latin-1，常见的fallback编码）
    result = g_convert(str, -1, "UTF-8", "ISO-8859-1", &bytes_read, &bytes_written, &error);
    if (result && !error) {
        return result;
    }
    if (error) {
        g_error_free(error);
        error = NULL;
    }
#endif
    
    // 如果所有转换都失败，返回原字符串的副本（至少保证内存安全）
    g_free(result);
    return g_strdup(str);
}

/**
 * @brief 检查并转换字符串编码为UTF-8（用于文件内容，内部使用）
 * @param str 输入字符串
 * @return 转换后的UTF-8字符串（如果是新分配的需要释放，如果是原字符串则不需要）
 * @note 这个函数主要用于文件内容，返回的指针可能指向原字符串或新分配的字符串
 */
const gchar* check_encoding(const gchar* str)
{
    if (!str) {
        return "";
    }
    
    // 如果已经是有效的UTF-8，直接返回
    if (g_utf8_validate(str, -1, NULL)) {
        return str;
    }
    
    // 对于文件内容，尝试转换但返回静态字符串（调用者会管理内存）
    gchar* result = convert_to_utf8(str);
    // 注意：这里返回的字符串需要调用者释放，但为了兼容现有代码，
    // 这里直接返回，调用者需要检查返回值是否等于原字符串
    return result ? result : str;
}

/**
 * @brief 从文件中读取文本内容
 * @param file_path 文件路径
 * @return 文件内容字符串（需要调用者释放内存）
 */
gchar* read_from_file(const gchar* file_path)
{
    if (!file_path) {
        return NULL;
    }
    // 归一化路径，避免混用分隔符导致打开失败
    gchar* normalized = normalize_path_separators(file_path);
    
    gchar* contents = NULL;
    gsize length = 0;
    GError* error = NULL;
    
    // 使用 GLib 的文件读取函数
    if (g_file_get_contents(normalized, &contents, &length, &error)) {
        // 检查编码并转换
        if (!g_utf8_validate(contents, -1, NULL)) {
            // 不是有效的UTF-8，尝试转换
            gchar* converted = convert_to_utf8(contents);
            g_free(contents);
            g_free(normalized);
            return converted;
        }
        g_free(normalized);
        return contents;
    } else {
        lyric_log_error("read_from_file: failed to read file %s: %s", normalized, error->message);
        g_error_free(error);
        g_free(normalized);
        return NULL;
    }
}

/**
 * @brief 写入文本内容到文件
 * @param file_path 文件路径
 * @param lyric 要写入的文本内容
 */
void write_to_file(const gchar* file_path, const gchar* lyric)
{
    if (!file_path || !lyric) {
        return;
    }
    // 归一化路径
    gchar* normalized = normalize_path_separators(file_path);
    GError* error = NULL;
    if (!g_file_set_contents(normalized, lyric, -1, &error)) {
        lyric_log_error("write_to_file: failed to write file %s: %s", normalized, error->message);
        g_error_free(error);
    }
    g_free(normalized);
}

/**
 * @brief 获取歌词文件路径
 * @param track_uri 音频文件路径
 * @param suffix 文件后缀
 * @return 歌词文件路径（需要调用者释放内存）
 */
gchar* get_lrc_path(const gchar* track_uri, const gchar* suffix) {
    if (!track_uri || !suffix) {
        return NULL;
    }
    // 先归一化输入路径
    gchar* norm_input = normalize_path_separators(track_uri);
    // 使用 GLib 的路径处理函数
    gchar* basename = g_path_get_basename(norm_input);
    gchar* dirname = g_path_get_dirname(norm_input);
    
    // 查找最后一个点号
    gchar* last_dot = g_strrstr(basename, ".");
    gchar* result;
    
    if (last_dot) {
        // 替换扩展名
        gchar* name_without_ext = g_strndup(basename, last_dot - basename);
        gchar* filename = g_strconcat(name_without_ext, suffix, NULL);
        result = g_build_filename(dirname, filename, NULL);
        g_free(name_without_ext);
        g_free(filename);
    } else {
        // 没有扩展名，直接添加后缀
        gchar* filename = g_strconcat(basename, suffix, NULL);
        result = g_build_filename(dirname, filename, NULL);
        g_free(filename);
    }
    
    g_free(basename);
    g_free(dirname);
    // 返回前再次归一化，确保分隔符一致
    gchar* normalized = normalize_path_separators(result);
    g_free(result);
    return normalized;
}

gchar* normalize_path_separators(const gchar* path) {
    if (!path) {
        return NULL;
    }
    // 将 '/' 和 '\\' 全部替换为当前平台分隔符
    gchar* copy = g_strdup(path);
    g_strdelimit(copy, "\\/", G_DIR_SEPARATOR);
    return copy;
}

/**
 * @brief 从音频文件旁边获取歌词文件
 * @param track_location 音频文件路径
 * @return 解析后的歌词结构体，包含歌词内容和是否为同步歌词的标志
 */
struct parsed_lyrics get_lyrics_next_to_file(const gchar* track_location) {
    struct parsed_lyrics result = {NULL, FALSE};
    
    if (!track_location) {
        return result;
    }

    gchar* lrc_path = get_lrc_path(track_location, ".lrc");
    gchar* txt_path = get_lrc_path(track_location, ".txt");
    
    // 尝试打开.lrc文件
    gchar* lyrics = read_from_file(lrc_path);
    if (lyrics) {
        result.lyrics = lyrics;
        result.sync = TRUE;
    } else {
        // 如果.lrc文件不存在，尝试打开.txt文件
        lyrics = read_from_file(txt_path);
        if (lyrics) {
            result.lyrics = lyrics;
            result.sync = TRUE;
        }
    }
    
    g_free(lrc_path);
    g_free(txt_path);
    return result;
}

/**
 * @brief 将毫秒数转换为歌词时间戳格式
 * @param number 毫秒数
 * @return 格式化的时间戳字符串，格式为[mm:ss.xx]（需要调用者释放内存）
 */
gchar* timestamps(gint number) {
    // 计算分钟、秒和毫秒部分
    gint seconds = number / 1000;
    number = number / 10;
    number %= 100;
    gint minutes = seconds / 60;
    seconds %= 60;

    // 使用 GLib 的字符串格式化函数
    return g_strdup_printf("[%02d:%02d.%02d]", minutes, seconds, number);
}

/**
 * @brief libcurl写入回调函数
 * @param contents 接收到的数据内容
 * @param size 数据块大小
 * @param nmemb 数据块数量
 * @param userp 用户数据指针（通常是GString指针）
 * @return 实际处理的字节数
 */
size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    GString* buffer = (GString*)userp;
    g_string_append_len(buffer, (gchar*)contents, size * nmemb);
    return size * nmemb;
}

/**
 * @brief 下载文本内容
 * @param slist HTTP头部列表
 * @param url 要下载的URL
 * @return 下载的文本内容（需要调用者释放内存）
 */
gchar* text_downloader(curl_slist* slist, const gchar* url) {
    lyric_log_debug("text_downloader: starting download from URL: %s", url);
    
    CURL* curl_handle;
    curl_handle = curl_easy_init();
    GString* readBuffer = g_string_new("");
    
    if (!curl_handle) {
        lyric_log_error("text_downloader: failed to initialize curl handle");
        g_string_free(readBuffer, TRUE);
        return NULL;
    }
    
    // 设置curl选项
    CURLcode res;
    res = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30); // 减少超时时间到30秒
    if (res != CURLE_OK) {
        lyric_log_error("text_downloader: failed to set timeout: %s", curl_easy_strerror(res));
    }
    
    res = curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10); // 连接超时10秒
    if (res != CURLE_OK) {
        lyric_log_error("text_downloader: failed to set connect timeout: %s", curl_easy_strerror(res));
    }
    
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl_handle, CURLOPT_HEADER, 0);
    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, false);
    curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "GET");
    curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist);
    curl_easy_setopt(curl_handle, CURLOPT_URL, url);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, readBuffer);
    
    lyric_log_debug("text_downloader: curl options set, starting request...");
    
    // 执行请求
    res = curl_easy_perform(curl_handle);
    
    if (res != CURLE_OK) {
        lyric_log_error("text_downloader: curl_easy_perform failed: %s", curl_easy_strerror(res));
    } else {
        long response_code;
        curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
        lyric_log_debug("text_downloader: request completed, response code: %ld, content length: %zu", 
            response_code, readBuffer->len);
    }
    
    curl_easy_cleanup(curl_handle);
    
    lyric_log_debug("text_downloader: returning content of length: %zu", readBuffer->len);
    gchar* result = g_string_free(readBuffer, FALSE);
    return result;
}

/**
 * @brief 去除字符串左侧空白字符
 * @param str 要处理的字符串
 * @return 处理后的字符串（需要调用者释放内存）
 */
gchar* ltrim(const gchar* str) {
    if (!str) {
        return NULL;
    }
    
    const gchar* start = str;
    while (*start && g_ascii_isspace(*start)) {
        start++;
    }
    
    return g_strdup(start);
}

/**
 * @brief 去除字符串右侧空白字符
 * @param str 要处理的字符串
 * @return 处理后的字符串（需要调用者释放内存）
 */
gchar* rtrim(const gchar* str) {
    if (!str) {
        return NULL;
    }
    
    gchar* result = g_strdup(str);
    gchar* end = result + strlen(result) - 1;
    
    while (end >= result && g_ascii_isspace(*end)) {
        *end = '\0';
        end--;
    }
    
    return result;
}

/**
 * @brief 去除字符串两侧空白字符
 * @param str 要处理的字符串
 * @return 处理后的字符串（需要调用者释放内存）
 */
gchar* trim(const gchar* str) {
    if (!str) {
        return NULL;
    }
    
    gchar* temp = ltrim(str);
    gchar* result = rtrim(temp);
    g_free(temp);
    return result;
}

/**
 * @brief 递归遍历目录，支持文件后缀筛选
 * @param dir_path 目录路径
 * @param file_list 存储文件路径的链表指针
 * @param extensions 允许的文件后缀数组
 * @param ext_count 后缀数量
 */
void traverse_directory_ext(const gchar* dir_path, GList** file_list, const gchar** extensions, gsize ext_count) {
    GError* error = NULL;
    GDir* dir = g_dir_open(dir_path, 0, &error);

    if (!dir) {
        g_printerr("Error opening %s: %s\n", dir_path, error->message);
        g_error_free(error);
        return;
    }

    const gchar* entry;
    while ((entry = g_dir_read_name(dir)) != NULL) {
        gchar* full_path = g_build_filename(dir_path, entry, NULL);

        if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) {
            traverse_directory_ext(full_path, file_list, extensions, ext_count);
            g_free(full_path);
        }
        else {
            // 检查文件后缀是否匹配
            gboolean match = FALSE;

            // 如果没有指定后缀，添加所有文件
            if (ext_count == 0) {
                match = TRUE;
            }
            else {
                // 获取文件后缀（小写）
                const gchar* dot = std::strrchr(entry, '.');
                if (dot) {
                    gchar* file_ext = g_ascii_strdown(dot + 1, -1);  // 跳过点号

                    // 检查是否在允许的后缀列表中
                    for (gsize i = 0; i < ext_count; i++) {
                        gchar* allowed_ext = g_ascii_strdown(extensions[i], -1);
                        if (g_str_equal(file_ext, allowed_ext)) {
                            match = TRUE;
                            g_free(allowed_ext);
                            break;
                        }
                        g_free(allowed_ext);
                    }
                    g_free(file_ext);
                }
            }

            if (match) {
                *file_list = g_list_append(*file_list, full_path);
            }
            else {
                g_free(full_path);
            }
        }
    }
    g_dir_close(dir);
}